///
/// ArmyBodger 3
/// (c)2010 richyp
///
using System;
using System.Drawing;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Xml.Linq;
using System.Xml.XPath;
using ArmyBodger.Core.Utilities;

namespace ArmyBodger.Core {
    /// <summary>
    /// Parses a Game System folder
    /// </summary>
    public class GameSystemParser {
        /// <summary>
        /// Entry point for the Game System
        /// </summary>
        public const string GAME_SYSTEM_MAIN_FILE = "index.xml";
        /// <summary>
        /// EquipmentParser to parse the global equipment entries
        /// </summary>
        protected EquipmentParser equipmentParser = new EquipmentParser();
        /// <summary>
        /// The ScriptEngine instance
        /// </summary>
        public ScriptCore ScriptCore { get; set; }
        /// <summary>
        /// Load the GameSystem from the specified path.
        /// The path must contain GAME_SYSTEM_MAIN_FILE or it won't work
        /// </summary>
        /// <param name="path">The path to parse</param>
        /// <returns>A GameSystem object parsed from the specified folder</returns>
        public GameSystem ParseGameSystemPath(string path) {
            if (!Directory.Exists(path)) {
                throw new GameSystemParserException("Game System path: " + path + " is not valid");
            }
            if (!File.Exists(path + "/" + GAME_SYSTEM_MAIN_FILE)) {
                throw new GameSystemParserException(
                    "Game System path: " + path + " does not contain a " + GAME_SYSTEM_MAIN_FILE + " file."
                    );
            }
            XDocument doc = null;
            try {
                doc = XDocument.Load(path + "/" + GAME_SYSTEM_MAIN_FILE);
            } catch (Exception ex) {
                throw new GameSystemParserException("Game System File: " + GAME_SYSTEM_MAIN_FILE + " is not valid");
            }
            if (doc.Root.Name != "system") {
                throw new GameSystemParserException(
                    "Game System File: " + GAME_SYSTEM_MAIN_FILE + " is not in the correct format"
                    ); 
            }
            GameSystem gs = new GameSystem();
            gs.Path = path;
            this.ParseHeader(gs, doc);
            this.ParseGlobals(gs, doc);
            this.ParseScriptFiles(gs, doc);
            return gs;
        }
        /// <summary>
        /// Parse the header segment of the Game System main file
        /// </summary>
        /// <param name="gameSystem">The GameSystem object to populate</param>
        /// <param name="doc">The XML Document to parse</param>
        protected void ParseHeader(GameSystem gameSystem, XDocument doc) {
            foreach (XElement element in doc.XPathSelectElements("system/header/*")) {
                gameSystem.Header.Properties.Add(
                    Helpers.ConvertToSentenceCase(element.Name.ToString()), element.Value
                    );
            }
            if (gameSystem.Header.Icon.ToString() != "False") {
                if (File.Exists(gameSystem.Path + "/" + gameSystem.Header.Icon)) {
                    gameSystem.Icon = Image.FromFile(gameSystem.Path + "/" + gameSystem.Header.Icon); 
                }
            }
        }
        /// <summary>
        /// Load the global equipment entries from this Game System
        /// </summary>
        /// <param name="gameSystem">The GameSystem object to populate</param>
        /// <param name="doc">The XML Document to parse</param>
        protected void ParseGlobals(GameSystem gameSystem, XDocument doc) {
            foreach (XElement element in doc.XPathSelectElements("system/global/items/file")) {
                gameSystem.Globals.AddRange(this.equipmentParser.ParseEquipmentFile(gameSystem.Path + "/" + element.Value));
            }
        }
        /// <summary>
        /// Load the game system specific script functions
        /// </summary>
        /// <param name="gameSystem">GameSystem used</param>
        /// <param name="doc">XML Document</param>
        protected void ParseScriptFiles(GameSystem gameSystem, XDocument doc) {
            foreach (XElement element in doc.XPathSelectElements("system/scripts/file")) {
                this.ScriptCore.LoadFile(gameSystem.Path + "/" + element.Value);
            }
        }
    }
}
